<!---
Copyright: (c) 2006 The MachBlog Authors
Authors: Matt Woodward (mpwoodward@gmail.com) & Peter J. Farrell (pjf@maestropublishing.com)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. 
You may obtain a copy of the License at 

http://www.apache.org/licenses/LICENSE-2.0 

Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
See the License for the specific language governing permissions and 
limitations under the License.

$Id: CommentListener.cfc 1189 2007-07-13 21:12:45Z pfarrell $

Notes:
This listener is autowired by ColdSpring.
--->
<cfcomponent
	displayname="CommentListener"
	extends="MachII.framework.Listener"
	output="false"
	hint="CommentListener for MachBlog.">

	<!---
	INITIALIZATION / CONFIGURATION
	--->
	<cffunction name="configure" access="public" output="false" returntype="void" 
		hint="Configures this listener as part of the Mach-II framework.">
		<!--- Does nothing. --->
	</cffunction>

	<cffunction name="setCommentService" access="public" output="false" returntype="void"
		hint="Dependency: injected">
		<cfargument name="commentService" type="machblog.org.machblog.comment.CommentService" required="true" />
		<cfset variables.commentService = arguments.commentService />
	</cffunction>	
	<cffunction name="getCommentService" access="private" output="false" returntype="machblog.org.machblog.comment.CommentService">
		<cfreturn variables.commentService />
	</cffunction>
	
	<cffunction name="setEntryService" access="public" output="false" returntype="void"
		hint="Dependency: injected">
		<cfargument name="entryService" type="machblog.org.machblog.entry.EntryService" required="true" />
		<cfset variables.entryService = arguments.entryService />
	</cffunction>	
	<cffunction name="getEntryService" access="private" output="false" returntype="machblog.org.machblog.entry.EntryService">
		<cfreturn variables.entryService />
	</cffunction>
	
	<cffunction name="setUdfs" access="public" output="false" returntype="void">
		<cfargument name="udfs" type="machblog.org.machblog.utils.udfs" required="true" />
		<cfset variables.udfs = arguments.udfs />
	</cffunction>
	<cffunction name="getUdfs" access="public" output="false" returntype="machblog.org.machblog.utils.udfs">
		<cfreturn variables.udfs />
	</cffunction>
	
	<!---
	PUBLIC FUNCTIONS - GATEWAY RELATED
	--->
	<cffunction name="getCommentsByEntryId" access="public" output="false" returntype="query" 
			hint="Returns a query object containing comments for an entry.">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		<cfreturn getCommentService().getCommentsByEntryId(arguments.event.getArg("entryId")) />
	</cffunction>
	
	<cffunction name="getRecentComments" access="public" output="false" returntype="query" 
		hint="Returns a query object containing recent comments across all entries.">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		
		<cfset var numToGet = getProperty("numRecentCommentsToDisplay") />
		<cfset var includeInactive = true />
		
		<cfif arguments.event.isArgDefined("numCommentsToGet")>
			<cfset numToGet = arguments.event.getArg("numCommentsToGet") />
		</cfif>
		
		<cfif arguments.event.isArgDefined("includeInactiveComments")>
			<cfset includeInactive = arguments.event.getArg("includeInactiveComments") />
		</cfif>
		
		<cfreturn getCommentService().getRecentComments(numToGet, includeInactive) />
	</cffunction>
	
	<cffunction name="getAllComments" access="public" output="false" returntype="query" 
			hint="Returns a query object containing all comments across all entries.">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		
		<cfreturn getCommentService().getAllComments(includeInactive = true, 
														searchTerms = arguments.event.getArg("searchTerms", ""), 
														sortOrder = "DESC") />
	</cffunction>
	
	<cffunction name="getCommentCountByDate" access="public" output="false" returntype="numeric" 
			hint="Returns the comment count for a specific date. Defaults to current date.">
		<cfargument name="commentDate" type="date" required="false" default="#Now()#" />
		<cfreturn getCommentService().getCommentCount(arguments.commentDate) />
	</cffunction>

	<cffunction name="getTotalCommentCount" access="public" output="false" returntype="numeric" 
			hint="Returns the total number of comments in the blog">
		<cfreturn getCommentService().getCommentCount() />
	</cffunction>
	
	<cffunction name="getSubscriptionCount" access="public" output="false" returntype="numeric" 
			hint="Returns the total number of comment subscriptions across all comments.">
		<cfreturn getCommentService().getSubscriptionCount() />
	</cffunction>
	
	<cffunction name="deactivateCommentsByEntryId" access="public" output="false" returntype="void" hint="Deactivates comments for an entry">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		<cfreturn getCommentService().deactivateCommentsByEntryId(arguments.event.getArg("entryId")) />
	</cffunction>
	
	<cffunction name="activateCommentsByEntryId" access="public" output="false" returntype="void" hint="Activates comments for an entry">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		<cfreturn getCommentService().activateCommentsByEntryId(arguments.event.getArg("entryId")) />
	</cffunction>
	
	<cffunction name="deleteCommentsByEntryId" access="public" output="false" returntype="void" hint="Deletes comments for an entry">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		<cfreturn getCommentService().deleteCommentsByEntryId(arguments.event.getArg("entryId")) />
	</cffunction>
	
	<cffunction name="toggleCommentDisplay" access="public" output="false" returntype="void" 
			hint="Toggles the comment's display flag and announces the next event.">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		
		<!--- create the email subject and entry url --->
		<cfset var entryTitle = getEntryService().getEntryTitleById(arguments.event.getArg("entryId")) />
		<cfset var emailSubject = getProperty("resourceBundleService").getResourceBundle().getResource("newcommentemailsubject") & 
									" " & getProperty("blogHeaderTitle") & ": " & entryTitle />
		<cfset var entryUrl = "" />
		<cfset var unsubscribeText = getProperty("resourceBundleService").getResourceBundle().getResource("unsubscribefromcommentsmessage") />
		<cfset var unsubscribeUrl = "" />
		<cfset var moduleName = "" />
		<cfset var am = getAppManager() />
		
		<cfif StructKeyExists(am, "getModuleName")>
			<cfset moduleName = am.getModuleName() />
		</cfif>
		<cfset entryUrl = variables.udfs.buildUrl(moduleName, 'showEntry', 'entryId=' & arguments.event.getArg("entryId")) />
		<cfset unsubscribeUrl = variables.udfs.buildUrl(moduleName, 'unsubscribeFromComments', 'entryId=' & arguments.event.getArg("entryId")) />
		
		<cfset getCommentService().toggleCommentDisplay(arguments.event.getArg("commentId"), arguments.event.getArg("action")) />
		
		<cfset getCommentService().emailCommentNotification(arguments.event.getArg("commentId"), 
															arguments.event.getArg("entryId"), 
															entryTitle, 
															getProperty("notifyAdminOfComments"), 
															getProperty("emailAuthor"), 
															getProperty("emailComments"), 
															emailSubject, entryUrl, 
															unsubscribeText, unsubscribeUrl, 
															getProperty("resourceBundleService").getResourceBundle().getResource("commentby")) />

		<cfset announceEvent(arguments.event.getArg("exitEvent", "showBlogEntryForm"), arguments.event.getArgs()) />
	</cffunction>
	
	<cffunction name="toggleIpBlock" access="public" output="false" returntype="void" 
		hint="Adds or removes the IP passed in to/from the block list.">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		
		<cfset var exitEvent = arguments.event.getArg("exitEvent", "showBlogEntryForm") />
		<cfset getCommentService().toggleIpBlock(arguments.event.getArg("ipAddress"), 
																arguments.event.getArg("action")) />
		
		<cfset announceEvent(exitEvent) />
	</cffunction>
	
	<cffunction name="deleteComments" access="public" output="false" returntype="void" 
		hint="Deletes multiple comments using the ids passed in">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		
		<cfset getCommentService().deleteComments(arguments.event.getArg("deleteIds")) />
		
		<cfset announceEvent(arguments.event.getArg("exitEvent", "showBlogEntryForm"), arguments.event.getArgs()) />
	</cffunction>
	
	<!---
	PUBLIC FUNCTIONS - DAO RELATED
	--->
	<cffunction name="getComment" access="public" output="false" returntype="machblog.org.machblog.comment.Comment"
		hint="Retrieves a comment by ID.">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		
		<cfreturn getCommentService().getCommentById(arguments.event.getArg("commentId", "")) />
	</cffunction>
	
	<cffunction name="processCommentForm" access="public" output="false" returntype="void"
			hint="Processes the comment form and announces the next event.">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		
		<cfset var comment = arguments.event.getArg("comment") />
		<cfset var entryTitle = getEntryService().getEntryTitleById(comment.getEntryId()) />
		<cfset var message = "" />
		<cfset var emailSubject = getProperty("resourceBundleService").getResourceBundle().getResource("newcommentemailsubject") & 
									" " & getProperty("blogHeaderTitle") & ": " & entryTitle />				
		<cfset var entryUrl = "" />
		<cfset var unsubscribeText = getProperty("resourceBundleService").getResourceBundle().getResource("unsubscribefromcommentsmessage") />
		<cfset var unsubscribeUrl = "" />
		<cfset var success = true />
		<cfset var moduleName = "" />
		<cfset var am = getAppManager() />
		
		<cfif StructKeyExists(am, "getModuleName")>
			<cfset moduleName = am.getModuleName() />
		</cfif>
		<cfset unsubscribeUrl =variables.udfs.buildUrl(moduleName, 'unsubscribeFromComments', 'entryId=' & comment.getEntryId()) />
		<cfset entryUrl = variables.udfs.buildUrl(moduleName, 'showEntry', 'entryId=' & comment.getEntryId()) />
		
		<!--- handle additional form stuff that couldn't be put in the event bean --->
		<!--- if this is a logged-in user, set the created by id --->
		<cfif getCommentService().getUserFacade().userExists() 
				AND getCommentService().getUserFacade().getUser().getUserId() NEQ "">
			<cfset comment.getAudit().setCreatedById(getCommentService().getUserFacade().getUser().getUserId()) />
		</cfif>
		
		<!--- set audit data values --->
		<cfset comment.getAudit().setDtCreated(getProperty("resourceBundleService").getLocaleUtils().toEpoch(Now())) />
		<cfset comment.getAudit().setIpCreated(CGI.REMOTE_ADDR) />
		
		<!--- set active flag based on blog settings --->
		<cfif getProperty("useCaptcha") OR getProperty("moderateComments") OR NOT getProperty("allowComments")>
			<cfset comment.getAudit().setIsActive(0) />
		<cfelse>
			<cfset comment.getAudit().setIsActive(1) />
		</cfif>
		
		<!--- handle mod data for update --->
		<cfif comment.getCommentId() NEQ "">
			<!--- only logged-in users can update comments --->
			<cfset comment.getAudit().setModifiedById(getCommentService().getUserFacade().getUser().getUserId()) />
			<cfset comment.getAudit().setDtModified(getProperty("resourceBundleService").getLocaleUtils().toEpoch(Now())) />
			<cfset comment.getAudit().setIpModified(CGI.REMOTE_ADDR) />
			
			<cfif arguments.event.isArgDefined("isActive") AND arguments.event.getArg("isActive")>
				<cfset comment.getAudit().setIsActive(arguments.event.getArg("isActive")) />
			<cfelse>
				<cfset comment.getAudit().setIsActive(0) />
			</cfif>
		</cfif>
		
		<cfif comment.getCommentId() EQ "">
			<cfset comment.setCommentId(createUUID()) />
			
			<cfif NOT getProperty("moderateComments")>
				<cfset comment.getAudit().setIsActive(1) />
			</cfif>

			<cfif getProperty("moderateComments")>
				<cfset message = message & " " & getProperty("resourceBundleService").getResourceBundle().getResource("commentmoderationmessage") />
			</cfif>

			<cfif getProperty("useCaptcha") AND arguments.event.isArgDefined("captchaMessage")>
				<cfset success = false />
				<cfset message = getProperty("resourceBundleService").getResourceBundle().getResource("captchafail") />
			<cfelse>
				<cfset getCommentService().createComment(comment) />
				<cfset message = getProperty("resourceBundleService").getResourceBundle().getResource("commentactionsuccessful") />

				<!--- if the comments don't need to be approved, notify comment subscribers that a comment was posted --->
				<cfif comment.getAudit().getIsActive()>
					<cfset getCommentService().emailCommentNotification(comment.getCommentId(), 
																		comment.getEntryId(), 
																		entryTitle, 
																		getProperty("notifyAdminOfComments"), 
																		getProperty("emailAuthor"), 
																		getProperty("emailComments"), 
																		emailSubject, entryUrl, 
																		unsubscribeText, unsubscribeUrl, 
																		getProperty("resourceBundleService").getResourceBundle().getResource("commentby")) />
				</cfif>
			</cfif>
		<cfelse>
			<cfset getCommentService().updateComment(comment) />
		</cfif>

		<cfset arguments.event.setArg("message", message) />
		
		<cfif success>
			<cfset arguments.event.removeArg("comment") />
			<cfset arguments.event.removeArg("commentId") />
			<cfset announceEvent("showComments", arguments.event.getArgs()) />
		<cfelse>
			<cfset comment.setCommentId("") />
			<cfset arguments.event.setArg("comment", comment) />
			<cfset announceEvent("showComments_error", arguments.event.getArgs()) />
		</cfif>
	</cffunction>
	
	<cffunction name="processCommentSubscriptionForm" access="public" output="false" returntype="void" 
			hint="Processes the comment subscription form and announces the next event">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		
		<cfset var comment = arguments.event.getArg("comment") />
		
		<cfset comment.setIsSubscribed(true) />
		<cfset comment.setSubscriptionOnly(true) />
		<cfset comment.setSubscriberEmailSent(true) />
		<cfset comment.getAudit().setDtCreated(getProperty("resourceBundleService").getLocaleUtils().toEpoch(Now())) />
		<cfset comment.getAudit().setIpCreated(CGI.REMOTE_ADDR) />
		<cfset comment.getAudit().setIsActive(true) />
		
		<cftry>
			<cfset getCommentService().createComment(comment) />
			<cfset arguments.event.setArg("message", getProperty("resourceBundleService").getResourceBundle().getResource("commentsubscriptionsucceeded")) />
			<cfcatch type="any">
				<cfset arguments.event.setArg("message", getProperty("resourceBundleService").getResourceBundle().getResource("commentsubscriptionfailed")) />
			</cfcatch>
		</cftry>
		
		<cfset announceEvent("showComments", arguments.event.getArgs()) />
	</cffunction>
	
	<cffunction name="unsubscribeFromComments" access="public" output="false" returntype="void" 
			hint="Handles unsubscribe links that are contained in the comment notification emails">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		
		<cfset var message = getProperty("resourceBundleService").getResourceBundle().getResource("unsubscribefromcommentssuccess") />
		
		<cftry>
			<cfset getCommentService().unsubscribe(arguments.event.getArg("entryId"), arguments.event.getArg("email")) />
			<cfcatch type="any">
				<cfset message = getProperty("resourceBundleService").getResourceBundle().getResource("unsubscribefromcommentsfailed") />
			</cfcatch>
		</cftry>
		
		<cfset arguments.event.setArg("message", message) />
		<cfset announceEvent("showHome_redirect", arguments.event.getArgs()) />
	</cffunction>
	
	<cffunction name="deleteComment" access="public" output="false" returntype="void" 
			hint="Deletes a comment and announces the next event">
		<cfargument name="event" type="MachII.framework.Event" required="true" />
		
		<cfset getCommentService().deleteComment(arguments.event.getArg("comment")) />
		
		<cfset arguments.event.setArg("message", getProperty("resourceBundleService").getResourceBundle().getResource("commentdeletesuccessmessage")) />
		<cfset announceEvent("showComments", arguments.event.getArgs()) />
	</cffunction>
</cfcomponent>